﻿using System;
using System.ComponentModel;
using System.Security.Cryptography.X509Certificates;

namespace HW0324_1
{
  class Product
    {
        public string Name { get; set; }
        // int ID { get; set; }
        public Product(string name)
        {
            Name = name;
            //ID = id;
        }
        public override string ToString()
        {
            return "Product: " + Name;
        }
        public override bool Equals(object obj)
        {
            Product p = obj as Product;
            return p != null && p.Name == Name;
        }

        public override int GetHashCode()
        {
            throw new NotImplementedException();
        }
    }
    class Client
    {
        public string Name { get; set; }
        //public int ID { get; set; }
        public Client(string name)
        {
            Name = name;
            //ID = id;
        }
        public override string ToString()
        {
            return "Client: " + Name + " ";
        }
        public override bool Equals(object obj)
        {
            Client p = obj as Client;
            return p != null && p.Name == Name;
        }

        public override int GetHashCode()
        {
            throw new NotImplementedException();
        }
    }
    class OrderDetails
    {
        public int Number { get; set; }
        public Product product;
        public Client client;
        public double Amount { get; set; }
        public OrderDetails()
        {
            Number = 0000;
            this.product = new Product("");
            this.client = new Client("");
            Amount = 0;
        }
        public OrderDetails(int number, Product product, Client client, double amount)
        {
            Number = number;
            this.product = product;
            this.client = client;
            Amount = amount;
        }
        public override string ToString()
        {
            return ("Order Number: "+Number.ToString()+"\n"+product.ToString()+"\n"+client.ToString()+"\n"+"Amount: "+Amount.ToString()+"\n");
        }
        public override bool Equals(object obj)
        {
            OrderDetails p = obj as OrderDetails;
            return p != null && p.Number == Number && product.Equals(p) && client.Equals(p) && p.Amount == Amount;
        }

        public override int GetHashCode()
        {
            throw new NotImplementedException();
        }
    }
    class Order
    {
        public OrderDetails orderDetails;
        public Order()
        {
            orderDetails = new OrderDetails();
        }
        public Order(int number, Product product, Client client, double amount)
        {
            orderDetails = new OrderDetails(); // Don't forget this one!
            orderDetails.Number = number;
            orderDetails.product = product;
            orderDetails.client = client;
            orderDetails.Amount = amount;
        }
        public override string ToString()
        {
            return "-----------Order Details-----------\n" + orderDetails.ToString()+ "-----------------------------------\n";
        }
        public override bool Equals(object obj)
        {
            Order p = obj as Order;
            return orderDetails.Equals(p);
        }

        public override int GetHashCode()
        {
            throw new NotImplementedException();
        }
    }
    class OrderService
    {
        List<Order> orders;
        public OrderService()
        {
            orders = new List<Order>();
        }
        public void Output()
        {
            foreach (Order o in orders)
            {
                Console.Write(o.ToString());
            }
        }
        public void Add(int number, string pn, string cn, double amount)
        {
            orders.Add(new Order(number, new Product(pn), new Client(cn), amount)); //Don't forget the new!
        }
        public delegate void Process(List<Order> x);
        public bool Find_n(int number, ref List<Order> result, Process p)
        {
            result.Clear();
            var os =
                from o in orders
                where o.orderDetails.Number == number
                orderby o.orderDetails.Number
                select o;
            foreach (var x in os)
            {
                result.Add(x);
            }
            if (result.Count == 0)
                return false;
            p(result);
            return true;
        }
        public void Find_p(string pn, ref List<Order> result, Process p)
        {
            result.Clear();
            var os =
                from o in orders
                where o.orderDetails.product.Equals(new Product(pn))
                orderby o.orderDetails.Number
                select o;
            foreach (var x in os)
            {
                result.Add(x);
            }
            p(result);
        }
        public void Find_c(string cn, ref List<Order> result, Process p)
        {
            result.Clear();
            var os =
                from o in orders
                where o.orderDetails.client.Equals(new Client(cn))
                orderby o.orderDetails.Number
                select o;
            foreach (var x in os)
            {
                result.Add(x);
            }
            p(result);
        }
        public void Find_a(double amount, ref List<Order> result, Process p)
        {
            result.Clear();
            var os =
                from o in orders
                where o.orderDetails.Amount == amount
                orderby o.orderDetails.Number
                select o;
            foreach (var x in os)
            {
                result.Add(x);
            }
            p(result);
        }
        public void Delete(ref List<Order> result)
        {
            try
            {
                if (result.Count == 0)
                    throw new Exception("Err: No such order found. ");
                else
                {
                    foreach (var x in result)
                    {
                        for (int i = 0; i < orders.Count; i++)
                        {
                            if (orders[i] == x)
                            {
                                orders.RemoveAt(i);
                                break;
                            }
                        }
                        
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        public void Modify(ref List<Order> result, int number, string pn, string cn, double amount)
        {
            try
            {
                if (result.Count == 0)
                    throw new Exception("Err: No such order found. ");
                else
                {
                    foreach (var x in result)
                    {
                        for (int i = 0; i < orders.Count; i++)
                        {
                            if (orders[i] == x)
                            {
                                orders.RemoveAt(i);
                                orders.Add(new Order(number, new Product(pn), new Client(cn), amount));
                                break;
                            }
                        }

                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        public void Sort_num()
        {
            var os =
                from o in orders
                orderby o.orderDetails.Number
                select o;
            List<Order> result = new List<Order>();
            foreach (var x in os)
            {
                result.Add(x);
            }
            orders = result.OrderBy(o => o.orderDetails.Number).ToList();
        }
        public void Sort_amo()
        {
            var os =
                from o in orders
                orderby o.orderDetails.Number
                select o;
            List<Order> result = new List<Order>();
            foreach (var x in os)
            {
                result.Add(x);
            }
            orders = result.OrderBy(o => o.orderDetails.Amount).ToList();
        }
    }
    class ProcessFunctions
    {
        public static void print(List<Order> orders)
        {
            if (orders.Count == 0)
                return;
            else
            {
                foreach(var x in orders)
                {
                    Console.Write(x.ToString());
                }
            }
        }
        public static void none(List<Order> orders)
        {
            ;
        }
    }
    class Program
    {
        static void Main()
        {
            Console.WriteLine("...Creating a list of orders...\n");
            OrderService order = new OrderService();
            order.Add(0001, "iPhone 14 Pro", "John", 8999);
            order.Add(0002, "iPhone 14 Pro Max", "YiLin", 10899);
            order.Add(0003, "iPhone 14 Pro", "Linda", 6999);
            order.Add(0004, "Airpods Max", "Sean", 4399);
            order.Add(0005, "HomePod", "Mariah", 3499);
            order.Add(0006, "MacBook Pro 13", "Sean", 10699);
            Console.WriteLine("...Printing this list of orders...\n");
            order.Output();
            bool exit = false;
            while (true)
            {
                Console.WriteLine("\n********************************************************");
                Console.WriteLine("*************************Menus**************************");
                Console.Write("\na. Search using Order Number\nb. Search using Product Name\nc. Search using Client Name\nd. Search using Order Amount\n\n" +
                    "e. Delete using Order Number\nf. Delete using Product Name\ng. Delete using Client Name\nh. Delete using Order Amount\n\n" +
                    "i. Modify using Order Number\nj. Modify using Product Name\nl. Modify using Client Name\nm. Search using Order Amount\n\n" +
                    "n. Add Order\no. Sort Order by Order Number\np. Sort by Order Amount\nq. Output Order\nr. Exit\n\n" + "*************************Menus**************************\n" +
                    "********************************************************\nYour choice: ");
                string choice = Console.ReadLine();
                List<Order> temp = new List<Order>();
                switch (choice)
                {
                    case "a":
                        Console.Write("Input a order number: ");
                        int num = int.Parse(Console.ReadLine());
                        Console.WriteLine();
                        order.Find_n(num, ref temp, ProcessFunctions.print);
                        break;
                    case "b":
                        Console.Write("Input a product name: ");
                        string pn = Console.ReadLine();
                        Console.WriteLine();
                        order.Find_p(pn, ref temp, ProcessFunctions.print);
                        break;
                    case "c":
                        Console.Write("Input a client name: ");
                        string cn = Console.ReadLine();
                        Console.WriteLine();
                        order.Find_c(cn, ref temp, ProcessFunctions.print);
                        break;
                    case "d":
                        Console.Write("Input a number of amount: ");
                        double a = double.Parse(Console.ReadLine());
                        Console.WriteLine();
                        order.Find_a(a, ref temp, ProcessFunctions.print);
                        break;
                    case "e":
                        Console.Write("Input a order number: ");
                        int num2 = int.Parse(Console.ReadLine());
                        order.Find_n(num2, ref temp, ProcessFunctions.none);
                        order.Delete(ref temp);
                        break;
                    case "f":
                        Console.Write("Input a product name: ");
                        string pn2 = Console.ReadLine();
                        order.Find_p(pn2, ref temp, ProcessFunctions.none);
                        order.Delete(ref temp);
                        break;
                    case "g":
                        Console.Write("Input a client name: ");
                        string cn2 = Console.ReadLine();
                        order.Find_c(cn2, ref temp, ProcessFunctions.none);
                        order.Delete(ref temp);
                        break;
                    case "h":
                        Console.Write("Input a number of amount: ");
                        double a2 = double.Parse(Console.ReadLine());
                        order.Find_a(a2, ref temp, ProcessFunctions.none);
                        order.Delete(ref temp);
                        break;
                    case "i":
                        Console.Write("Input a order number: ");
                        int num3 = int.Parse(Console.ReadLine());
                        Console.Write("What you want the order number to be: ");
                        int newNum = int.Parse(Console.ReadLine());
                        Console.Write("What you want the product name to be: ");
                        string newPN = Console.ReadLine();
                        Console.Write("What you want the client name to be: ");
                        string newCN = Console.ReadLine();
                        Console.Write("What you want the amount of the order to be: ");
                        double newA = double.Parse(Console.ReadLine());
                        order.Find_n(num3, ref temp, ProcessFunctions.none);
                        order.Modify(ref temp, newNum, newPN, newCN, newA);
                        break;
                    case "j":
                        Console.Write("Input a product name: ");
                        string pn3 = Console.ReadLine();
                        Console.Write("What you want the order number to be: ");
                        int newNum2 = int.Parse(Console.ReadLine());
                        Console.Write("What you want the product name to be: ");
                        string newPN2 = Console.ReadLine();
                        Console.Write("What you want the client name to be: ");
                        string newCN2 = Console.ReadLine();
                        Console.Write("What you want the amount of the order to be: ");
                        double newA2 = double.Parse(Console.ReadLine());
                        order.Find_p(pn3, ref temp, ProcessFunctions.none);
                        order.Modify(ref temp, newNum2, newPN2, newCN2, newA2);
                        break;
                    case "l":
                        Console.Write("Input a product name: ");
                        string cn3 = Console.ReadLine();
                        Console.Write("What you want the order number to be: ");
                        int newNum3 = int.Parse(Console.ReadLine());
                        Console.Write("What you want the product name to be: ");
                        string newPN3 = Console.ReadLine();
                        Console.Write("What you want the client name to be: ");
                        string newCN3 = Console.ReadLine();
                        Console.Write("What you want the amount of the order to be: ");
                        double newA3 = double.Parse(Console.ReadLine());
                        order.Find_c(cn3, ref temp, ProcessFunctions.none);
                        order.Modify(ref temp, newNum3, newPN3, newCN3, newA3);
                        break;
                    case "m":
                        Console.Write("Input a order number: ");
                        double a3 = double.Parse(Console.ReadLine());
                        Console.Write("What you want the order number to be: ");
                        int newNum4 = int.Parse(Console.ReadLine());
                        Console.Write("What you want the product name to be: ");
                        string newPN4 = Console.ReadLine();
                        Console.Write("What you want the client name to be: ");
                        string newCN4 = Console.ReadLine();
                        Console.Write("What you want the amount of the order to be: ");
                        double newA4 = double.Parse(Console.ReadLine());
                        order.Find_a(a3, ref temp, ProcessFunctions.none);
                        order.Modify(ref temp, newNum4, newPN4, newCN4, newA4);
                        break;
                    case "n":
                        Console.WriteLine("Add an order: ");
                        Console.Write("What you want the order number to be: ");
                        int newNum5 = int.Parse(Console.ReadLine());
                        Console.Write("What you want the product name to be: ");
                        string newPN5 = Console.ReadLine();
                        Console.Write("What you want the client name to be: ");
                        string newCN5 = Console.ReadLine();
                        Console.Write("What you want the amount of the order to be: ");
                        double newA5 = double.Parse(Console.ReadLine());
                        order.Add(newNum5, newPN5, newCN5, newA5);
                        break;
                    case "o":
                        order.Sort_num();
                        break;
                    case "p":
                        order.Sort_amo();
                        break;
                    case "q":
                        Console.WriteLine();
                        order.Output();
                        break;
                    case "r":
                        exit = true;
                        break;
                }
                if (exit)
                    break;
            }
        }
    }
}